package drp.snowbell.annotation;

import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.lang.annotation.Annotation;
import java.net.URL;
import java.net.URLClassLoader;
import java.net.URLDecoder;
import java.util.Collection;
import java.util.Enumeration;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

import drp.snowbell.cfg.Constants;
import drp.snowbell.entity.IEntity;
import drp.snowbell.entity.IPart;
import drp.snowbell.exception.CatchException;


/**
 * class加载器
 * 
 * @author wuhj
 * 
 */
public class AnnotationClassLoader extends URLClassLoader {

	public AnnotationClassLoader(URL url, ClassLoader parent) {
		this(new URL[] { url }, parent);
	}

	public AnnotationClassLoader(URL[] urls, ClassLoader parent) {
		super(urls, parent);
		// Collection<File> fileList = getAllFiles(urls);
		// for (File file : fileList) {
		// try {
		//
		// URL url = file.toURI().toURL();
		// this.addURL(url);
		// } catch (MalformedURLException e) {
		// e.printStackTrace();
		// }
		// }
	}

	public void loadPartly(URL[] partialUrls, Collection<Class<? extends IEntity>> outEntities, Collection<Class<? extends IPart>> outParts) {
		for (URL url : partialUrls) {
			String encodePath = url.getFile();
			String decodePath = null;
			try {
				decodePath = URLDecoder.decode(encodePath, Constants.DEFAULT_CHARSET);
			} catch (UnsupportedEncodingException e1) {
				e1.printStackTrace();
				continue;
			}
			File file = new File(decodePath);
			if (file.isDirectory()) {
				continue;
			}
			JarFile jar = null;
			try {
				jar = new JarFile(file);
			} catch (IOException e) {
				e.printStackTrace();
				continue;
			}
			if (jar != null) {
				Enumeration<JarEntry> entries = jar.entries();
				while (entries.hasMoreElements()) {
					JarEntry entry = entries.nextElement();
					String name = entry.getName();
					// 如果是以/开头的
					if (name.charAt(0) == '/') {
						// 获取后面的字符串
						name = name.substring(1);
					}
					if (name.endsWith(".class") && !entry.isDirectory()) {
						name = name.replace("/", ".").substring(0, name.lastIndexOf("."));
						try {
							Class<?> clazz = this.loadClass(name);
							Annotation[] anns = clazz.getAnnotations();
							for (Annotation ann : anns) {
								if (ann instanceof AEntity) {
									if (IEntity.class.isAssignableFrom(clazz)) {
										@SuppressWarnings("unchecked")
										Class<? extends IEntity> entityClass = (Class<? extends IEntity>) clazz;
										outEntities.add(entityClass);
									} else {
										CatchException.warn(AnnotationClassLoader.class, clazz.getName() + " is not implements IEntity");
									}
								} else if (ann instanceof APart) {
									if (IPart.class.isAssignableFrom(clazz)) {
										@SuppressWarnings("unchecked")
										Class<? extends IPart> partClass = (Class<? extends IPart>) clazz;
										outParts.add(partClass);
									} else {
										CatchException.warn(AnnotationClassLoader.class, clazz.getName() + " is not implements IPart");
									}
								}
							}
						} catch (Exception e) {
							CatchException.take(AnnotationClassLoader.class, e);
						}
					}
				}
				try {
					jar.close();
				} catch (IOException e) {
					CatchException.take(AnnotationClassLoader.class, e);
				}
			}
		}
	}

	/**
	 * 根据Annotation获取Class
	 * 
	 * @param entities
	 *            实体的类
	 * @param parts
	 *            组件类
	 */
	public void loadAll(Collection<Class<? extends IEntity>> outEntities, Collection<Class<? extends IPart>> outParts) {
		URL[] urls = getURLs();
		loadPartly(urls, outEntities, outParts);
	}

	// private Collection<File> getAllFiles(URL[] urls) {
	// Collection<File> fileList = new ArrayList<File>();
	// for (URL url : urls) {
	// String encodePath = url.getPath();
	// String decodePath = null;
	// try {
	// decodePath = URLDecoder.decode(encodePath, Constants.DEFAULT_CHARSET);
	// } catch (UnsupportedEncodingException e1) {
	// e1.printStackTrace();
	// continue;
	// }
	// File file = new File(decodePath);
	// if (file.isDirectory()) {
	// getFiles(file, fileList);
	// } else {
	// fileList.add(file);
	// }
	// }
	// return fileList;
	// }
	//
	// private void getFiles(File rootDir, Collection<File> outFileList) {
	// if (rootDir.isDirectory()) {
	// File[] files = rootDir.listFiles();
	// for (File subFile : files) {
	// if (subFile.isDirectory()) {
	// getFiles(subFile, outFileList);
	// } else {
	// outFileList.add(subFile);
	// }
	// }
	// }
	// }
}
